package org.xgame.comm.async;

import java.util.ArrayDeque;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;

/**
 * 异步方式一步一步的执行,
 * 有点类似于 nodejs 中的 async 库 series 函数...
 * 主要目的是消除同步等待
 */
public final class AsyncStepByStep {
    /**
     * 绑定 Id
     */
    private final long _bindId;

    /**
     * 异步操作队列
     */
    private final Queue<IAsyncOperation> _asyncOpQueue = new ArrayDeque<>();

    /**
     * 在结束时继续执行
     */
    private IContinueWith _onOver_conX;

    /**
     * 结束过程在哪个线程执行
     */
    private Executor _onOver_exec;

    /**
     * 临时数值字典
     */
    private final Map<String, Object> _tempValMap = new ConcurrentHashMap<>();

    /**
     * 类参数构造器
     *
     * @param bindId 绑定 Id
     */
    public AsyncStepByStep(long bindId) {
        _bindId = bindId;
    }

    /**
     * 类参数构造器
     *
     * @param strBindId 绑定 Id
     */
    public AsyncStepByStep(String strBindId) {
        _bindId = BindIdHelper.getLongVal(strBindId);
    }

    /**
     * 添加下一步
     *
     * @param op 异步操作
     * @return this 指针
     */
    public AsyncStepByStep addNext(IAsyncOperation op) {
        if (null == op) {
            return this;
        }

        _asyncOpQueue.offer(op);
        return this;
    }

    /**
     * 当结束时执行
     *
     * @param conX 结束时继续执行
     * @param exec 结束过程在哪个线程执行
     * @return this 指针
     */
    public AsyncStepByStep onOver(IContinueWith conX, Executor exec) {
        _onOver_conX = conX;
        _onOver_exec = exec;
        return this;
    }

    /**
     * 执行下一步
     */
    public void doNext() {
        IAsyncOperation asyncOp = _asyncOpQueue.poll();
        IContinueWith conX = null;
        Executor exec = null;

        if (null == asyncOp) {
            conX = _onOver_conX;
            exec = _onOver_exec;
        }

        AsyncOperationProcessor.getInstance().process(
            _bindId, asyncOp, conX, exec
        );
    }

    /**
     * 获取临时数值
     *
     * @param key 关键字
     * @return 数值
     */
    public Object getTempVal(String key) {
        return _tempValMap.get(key);
    }

    /**
     * 设置临时数值
     *
     * @param key 关键字
     * @param val 数值
     * @return this 关键字
     */
    public AsyncStepByStep putTempVal(String key, Object val) {
        _tempValMap.put(key, val);
        return this;
    }

    /**
     * 停止
     */
    public void stop() {
        _tempValMap.clear();
        _asyncOpQueue.clear();
        _onOver_conX = null;
        _onOver_exec = null;
    }
}
